iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0
AI 自動化

AI × Digital Twin 打造線纜工廠自我進化系統系列 第 3

【Day 3】第 1,250 公尺的溫度,到底是幾度

  • 分享至 

  • xImage
  •  

昨天結尾留了一個問題:怎麼讓「第 1,250 公尺處的外徑」和「當時的料溫」,真的指向同一段線材。

今天來把它拆開。這一篇會是整個系列裡最不性感的一篇,但如果只能留一篇,我會留這篇。

先講一個我自己踩過的坑。

我第一次拿到某條押出線的歷史資料,很興奮,因為東西看起來很齊:PLC 的參數記錄有了,測徑儀的外徑記錄有了,兩邊都有時間戳記。我直接照時間 join 起來,丟進一個很簡單的模型,想看看料溫跟外徑的關係。

結果跑出來的係數是正的,而且還挺顯著。

意思是:料溫越高,外徑越大。

我拿去問現場,師傅的反應是先愣了一下,然後很客氣地說,應該是相反吧。溫度高料變稀,同樣牽引下來會被拉得更細,外徑應該是變小的。

模型不是準度差,模型是方向錯了。

而且它錯得很有自信。如果那時候我直接把這個模型包成一個「參數建議」的功能推到現場,它會建議師傅在外徑偏小的時候把溫度調低——這是會直接造成報廢的建議。

後來查出來,問題不在模型,在 join。

錯在哪

三件事疊在一起。

第一,兩套系統的時鐘不一樣。

PLC 的時鐘和量測系統的工控機,沒有對過 NTP。差了 40 幾秒。這件事沒有人知道,因為平常沒有人需要把兩邊的資料放在一起看。

第二,取樣頻率和記錄方式不一樣。

PLC 是每秒一筆,測徑儀是每 100ms 一筆但只在變化超過閾值時才寫。兩邊 join 的時候如果用最近鄰,會在某些區間配對到很遠的資料。

第三,也是最致命的:製程延遲。

這是昨天提過的。師傅在面板上把料溫調下去的那一秒,螺桿裡的料還是舊的溫度。那段真正被降溫的料,要走完螺桿剩餘段、模頭、氣隙、水槽,才會到測徑儀底下。這中間可能是 40 秒到 3 分鐘,看線速和水槽長度。

所以「時間 t 的料溫」對應的不是「時間 t 的外徑」,而是「時間 t + τ 的外徑」。

如果 τ 沒補,而現場又習慣在外徑偏大的時候降溫——那資料裡看到的就會是:降溫之後(但延遲還沒過去),外徑還是大的;等溫度回穩之後,外徑才變小。統計上就長成「溫度低 → 外徑大」,也就是我那個正係數的來源。

模型學到的不是物理,是操作員的反應習慣。 這在製程資料裡非常常見,而且非常難察覺,因為它看起來很合理、很顯著、很有解釋力。

正確的做法:不要用時間當主鍵

昨天說過,跨站唯一的共同座標是長度。其實在單站內也一樣。

正確的順序是:

原始訊號 (帶時間戳)
↓ 時鐘校正
↓ 統一取樣
↓ 累積長度換算
線材位置索引 (帶長度座標)
↓ 製程延遲補償
可用於建模的資料表

核心觀念:把所有訊號從「時間軸」搬到「線材長度軸」上。

時間會漂、會停(停機)、會因為線速不同而跟長度脫鉤;但一段線材的第 1,250 公尺,永遠是第 1,250 公尺。

累積長度怎麼算

最直接的來源是計米器(編碼器)。如果沒有,可以從牽引速度積分:

L(t) = ∫ v(t) dt

但要注意兩件事:速度訊號有雜訊,積分會累積誤差;停機時速度歸零,長度不該增加,但如果訊號有 offset,長度就會在停機時偷偷往前爬。實務上要定期用計米器或收線盤的實際長度去校正漂移。

延遲怎麼算

延遲不是一個固定值,它跟線速有關:

τ = D / v

D 是從該參數的作用位置到量測點的物理距離,v 是線速。

不同參數的 D 不一樣:

螺桿溫度:從螺桿中段 → 模頭 → 氣隙 → 水槽 → 測徑儀
模頭壓力:從模頭 → 之後全部
牽引速度:幾乎是即時影響拉伸比,但外徑穩定還是要走到測徑儀

所以每個參數要有自己的 D。這個 D 一開始用捲尺量個大概就好,後面可以用互相關(cross-correlation)去校正。

但更漂亮的做法是:如果你已經把所有訊號換算到長度軸上,延遲補償就變成單純的長度平移。

在長度軸上,「作用在第 L 公尺的料溫」對應「第 L 公尺的外徑」,不需要管線速變不變。線速變化造成的時間延遲變動,已經在換算的時候被吸收掉了。

這就是為什麼一定要先搬到長度軸,而不是在時間軸上硬補一個會變動的 τ。

程式碼

以下是一個可以跑的最小骨架。資料是我用物理關係合成的(含刻意加入的時鐘偏移和延遲),重點是流程,不是數字。

python
import numpy as np
import pandas as pd

============================================================

0. 合成資料:模擬真實工廠的兩套不同步系統

============================================================

rng = np.random.default_rng(42)

DT_PLC = 1.0 # PLC 取樣週期 (s)
N = 3600 # 一小時
CLOCK_OFFSET = 43.0 # 量測系統時鐘比 PLC 快 43 秒 (未知的偏差)
D_TEMP = 12.0 # 料溫作用點 → 測徑儀 的物理距離 (m)

t = np.arange(N) * DT_PLC

線速:有升速、穩定、和一次短暫停機

v = np.full(N, 3.0) # m/s
v[:60] = np.linspace(0, 3.0, 60) # 開機升速
v[1800:1860] = 0.0 # 停機 60 秒
v[1860:1920] = np.linspace(0, 3.0, 60) # 重新升速

料溫:基準 + 操作員的幾次調整 + 雜訊

temp = np.full(N, 185.0)
temp[900:] -= 3.0 # 操作員降 3 度
temp[2400:] += 2.0 # 之後又升 2 度
temp += rng.normal(0, 0.15, N)

真實物理:外徑 ~ 溫度負相關、線速負相關 (延遲後才顯現)

先在「線材長度軸」上生成真值,再反推到時間軸

L_plc = np.concatenate([[0], np.cumsum(v[:-1] * DT_PLC)]) # PLC 端累積長度

溫度作用在 L 公尺處的料,會在 L + D_TEMP 公尺處被量到

L_measured_of_temp = L_plc + D_TEMP

od_true = (2.500
- 0.012 * (temp - 185.0) # 溫度高 → 外徑小 (真實方向)
- 0.008 * (v - 3.0))

量測系統:自己的時間軸 (帶偏移)、自己的取樣、含雜訊

meas_time = t + CLOCK_OFFSET
od_meas = od_true + rng.normal(0, 0.004, N)

df_plc = pd.DataFrame({"ts": t, "melt_temp": temp, "line_speed": v})
df_meas = pd.DataFrame({"ts": meas_time,
"od": od_meas,
"L_meas": L_measured_of_temp}) # 量測端自己的計米

============================================================

1. 錯誤示範:直接照時間 merge

============================================================

naive = pd.merge_asof(df_meas.sort_values("ts"),
df_plc.sort_values("ts"),
on="ts", direction="nearest")
naive = naive.dropna()
c_naive = np.corrcoef(naive["melt_temp"], naive["od"])[0, 1]
print(f"[naive time-join] corr(temp, od) = {c_naive:+.3f}")
python

============================================================

2. 時鐘校正:用互相關找出兩套系統的時間偏移

============================================================

def estimate_clock_offset(sig_a, sig_b, max_lag=300):
"""兩個等間隔訊號,回傳 b 相對 a 的樣本延遲"""
a = (sig_a - sig_a.mean()) / (sig_a.std() + 1e-12)
b = (sig_b - sig_b.mean()) / (sig_b.std() + 1e-12)
lags = np.arange(-max_lag, max_lag + 1)
scores = [np.corrcoef(a[max_lag:-max_lag],
np.roll(b, l)[max_lag:-max_lag])[0, 1]
for l in lags]
return lags[int(np.argmax(np.abs(scores)))], np.max(np.abs(scores))

用線速當共同參考訊號最穩 (停機事件在兩邊都看得到)

這裡用 od 的變異當代理

lag, score = estimate_clock_offset(df_plc["melt_temp"].values,
df_meas["od"].values)
print(f"[clock] estimated lag = {lag} samples (score={score:.3f})")
python

============================================================

3. 搬到長度軸:這是核心

============================================================

def to_length_axis(ts, speed, signal, dt, grid_step=0.1):
"""把時間軸訊號重新取樣到等間距的線材長度軸"""
L = np.concatenate([[0], np.cumsum(speed[:-1] * dt)])
# 停機時 L 不前進 → 必須去除重複點,否則插值會爆
keep = np.concatenate([[True], np.diff(L) > 1e-9])
L_u, sig_u = L[keep], signal[keep]
grid = np.arange(L_u[0], L_u[-1], grid_step)
return grid, np.interp(grid, L_u, sig_u)

GRID = 0.1 # 每 10 公分一個資料點
L_grid, temp_L = to_length_axis(t, v, temp, DT_PLC, GRID)
_, spd_L = to_length_axis(t, v, v, DT_PLC, GRID)

量測值本來就帶自己的長度座標 (計米器),直接插到同一個 grid

od_L = np.interp(L_grid, df_meas["L_meas"].values, df_meas["od"].values)

============================================================

4. 延遲補償:在長度軸上只是「平移」

============================================================

shift = int(round(D_TEMP / GRID)) # 12 m / 0.1 m = 120 格
aligned = pd.DataFrame({
"L": L_grid[:-shift],
"melt_temp": temp_L[:-shift], # 作用在第 L 公尺
"line_speed": spd_L[:-shift],
"od": od_L[shift:], # 量到於第 L + D 公尺
})

c_aligned = np.corrcoef(aligned["melt_temp"], aligned["od"])[0, 1]
print(f"[length-axis aligned] corr(temp, od) = {c_aligned:+.3f}")
python

============================================================

5. 驗收:方向對不對

============================================================

import statsmodels.api as sm

X = sm.add_constant(aligned[["melt_temp", "line_speed"]])
res = sm.OLS(aligned["od"], X).fit()
print(res.params)

melt_temp 係數應為負 → 與物理一致

跑起來的結果大致是:naive join 的相關係數是正的(方向錯誤),搬到長度軸並補償延遲之後轉為負,且係數量級接近我設定的真值。

shift 那個 D_TEMP 在真實場景不會事先知道,做法是:掃一遍不同的 shift,找出讓相關性最強的那一個,再跟捲尺量出來的物理距離互相驗證。如果兩者差太多,通常代表你對製程的理解有問題,而不是資料有問題。 這是一個很好用的除錯訊號。

幾個現場才會遇到的坑

停機。 停機期間線材不動,但 PLC 還在記錄,料還在螺桿裡受熱。這段資料不能直接丟掉(它會影響重啟後那段料的品質),但也不能當成正常資料。我的做法是標記成獨立的 segment,建模時排除,但保留給「重啟品質預測」這個任務用。

盤與盤之間。 換盤的時候長度歸零,如果程式沒處理,累積長度會突然掉回 0,後面全錯。要有明確的 batch/reel 切分邏輯。

倒帶與剪除。 品檢剪掉一段之後,實體線材的長度座標就跟記錄不一致了。這一段必須被記錄下來,否則下游站的長度對應會整批偏移——這也是為什麼「剪掉三公里」這件事在資料上也是個事件,不只是損失。

計米器滑動。 編碼器靠摩擦輪,會滑。長距離下誤差會累積到公尺級。定期用收線盤總長校正。

為什麼這一天值得花

我知道這一篇沒有 AI、沒有模型、沒有漂亮的圖。

但 Day 1 那個問題還記得嗎:師傅說「做久了就知道」。

他腦袋裡有一張延遲表、一張因果圖,而且是對的。我們要做的系統如果連因果方向都會搞反,它憑什麼要求師傅相信它?

現場對系統的信任,只有一次機會。 一個建議錯一次方向,之後那個分頁就不會再被打開了。

資料對齊不是前置作業,它就是第一道品質關卡。

明天

有了對齊好的資料,Day 4 要進到「看得懂」這一層:

押出製程的物理到底長什麼樣?熔融、流動、模頭膨脹(die swell)、拉伸比、冷卻收縮——哪些部分可以寫成方程式,哪些只能靠資料補。

這是孿生模型的骨架,也決定了後面 AI 能不能回答「往哪個方向調」,而不只是「這捲大概會不良」。


上一篇
【Day 2】一條線從銅桿到出貨,要經過幾次不可逆
系列文
AI × Digital Twin 打造線纜工廠自我進化系統3
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言